package baseFx.common.collections.redis;

import baseFx.common.Func1T;
import baseFx.common.Stream;
import baseFx.common.collections.RemoteMap;
import baseFx.serialization.json.JsonUtils;
import redis.clients.jedis.Jedis;

import java.util.*;

public class RedisMap<V> implements RemoteMap<V> {
    private Class<V> clazz;
    private String name;
    private Jedis jedis;

    public RedisMap(Jedis jedis, Class<V> clazz, String name) {
        this.name = name;
        this.clazz = clazz;
        this.jedis = jedis;
    }

    protected String serialize(Object o) {
        return JsonUtils.toJson(o);
    }

    protected V deserialize(String content, Class<V> clazz) {
        return JsonUtils.toObject(content, clazz);
    }

    protected V deserialize(String content) {
        return deserialize(content, clazz);
    }

    @Override
    public int size() {
        return jedis.hlen(name).intValue();
    }

    @Override
    public boolean isEmpty() {
        return size() < 1;
    }

    @Override
    public boolean containsKey(Object key) {
        return jedis.hexists(name, key.toString());
    }

    @Override
    public boolean containsValue(Object value) {
        Func1T<V, Boolean> func = (Func1T<V, Boolean>) value;
        if (func == null) {
            throw new RuntimeException("请使用 Func1T<V, Boolean>。");
        }
        List<V> items = Stream.create(jedis.hvals(name)).map(this::deserialize).toList();
        for (V item : items) {
            if (func.execute(item)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public V get(Object key) {
        return deserialize(jedis.hget(name, key.toString()));
    }

    @Override
    public V put(String key, V value) {
        if (jedis.hset(name, key, serialize(value)) > 0) {
            return value;
        }
        return null;
    }

    @Override
    public V remove(Object key) {
        V item = get(key);
        if (item != null) {
            jedis.hdel(name, key.toString());
        }
        return item;
    }

    @Override
    public void putAll(Map<? extends String, ? extends V> m) {
        Map<String, String> map = new LinkedHashMap<>(m.size());
        for (String key : m.keySet()) {
            map.put(key, serialize(m.get(key)));
        }
        jedis.hset(name, map);
    }

    @Override
    public void clear() {
        jedis.del(name);
    }

    @Override
    public Set<String> keySet() {
        return jedis.hkeys(name);
    }

    @Override
    public Collection<V> values() {
        return Stream.create(jedis.hvals(name)).map(this::deserialize).toList();
    }

    @Override
    public Set<Entry<String, V>> entrySet() {
        Set<String> keys = keySet();
        Map<String, V> map = new HashMap<>(keys.size());
        for (String key : keys) {
            map.put(key, get(key));
        }
        return map.entrySet();
    }
}
